#import <appkit/Application.h>
#import <appkit/publicWraps.h>
#import <appkit/Control.h>
#import <appkit/TextField.h>
#import <appkit/ScrollView.h>
#import <appkit/Panel.h>
#import <appkit/graphics.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import "ToyWin.h"
#import "ToyView.h"
#import "TVController.h"
#import "strfunc.h"

#define  MiniIcon	"miniwin.tiff"
#define  DiffStep	22.0
#define  MinWinXSIZE	120.0
#define  MinWinYSIZE	32.0
#define  MinResizeXSIZE	200.0
#define  MinResizeYSIZE	150.0


@implementation ToyWin
- init: sender
{
	[NXApp loadNibSection:"ToyWin.nib" owner:self];
	[thiswindow setFreeWhenClosed: YES];
	controller = sender;
	scaleFactor = 1.0;
	imageFilename = NULL;
	miniFlag = mini_YET;
	return self;
}

- free
{
	// printf("FREE(%s)\n", imageFilename);
	if (imageFilename) free((void *)imageFilename);
	[super free];
	return nil;
}

- (char *)filename
{
	return imageFilename;
}

- (Window *)window
{
	return thiswindow;
}

- toyView
{
	return [scView docView];
}

/* ----------------------------------------------------------------
●ウィンドウサイズ決定方針
▽初期化時
    ・表示サイズ
	画像の大きさに合わせる。
	ただし、スクリーン幅より画像幅が大きい場合はスクリーン幅。
	高さも同様。
	また、しきい値(MinWinXSIZE=120, MinWinYSIZE=32)より小さい
	場合はしきい値を使う。
    ・表示位置
	ウィンドウの番号によって決定。
	ただし、スクリーン幅より画像幅が大きい場合は左端。
	スクリーン高より画像高が大きい場合は上端。
    ・リサイズの最大サイズ
	画像自体の大きさに合わせる。
	（今のところ、スクリーンの大きさで押さえることはしない）
    ・リサイズの最小サイズ
	定数(MinResizeXSIZE=200, MinResizeYSIZE=150)とする。
	ただし、これより画像が小さい場合は画像に合わせる。
▽イメージのリサイズ時
    ・表示サイズ
	元より大きくなった場合は変化なし。
	小さくなった場合で、元のウィンドウでは大きい場合は上の規則
	によって変化させる。
    ・表示位置
	変化なし。
    ・リサイズの最大・最小サイズ
	元のサイズが上の「リサイズの最小サイズ」より小さい場合は
	それを最小サイズとする。
	それ以外は上の通り。
---------------------------------------------------------------- */

- locateWindow: (int)width : (int)height init:(BOOL)is_init num:(int)wnum
	/* width, height  イメージの大きさ */
	/* is_init	ウィンドウの生成時処理かどうか */
	/* wnum		ウィンドウの番号 (init時のみ) */
{
	NXSize screenSize;
	NXSize req;	/* イメージを丸ごと表示できる大きさ */
	NXSize rsmin;	/* リサイズの最小サイズ */
	NXRect orig;	/* 現在のウィンドウの情報 */
	NXRect wrect;
	double xp, yp;	/* ウィンドウ位置 */

	[NXApp getScreenSize: &screenSize];
	req.width = ((MinWinXSIZE > width) ? MinWinXSIZE : width) + 23.0;
	req.height = ((MinWinYSIZE > height) ? MinWinYSIZE : height) + 74.0;
	rsmin.width = (req.width < MinResizeXSIZE)
			? req.width : MinResizeXSIZE;
	rsmin.height = (req.height < MinResizeYSIZE)
			? req.height : MinResizeYSIZE;
	wrect.size = req;
	if (is_init) {
		int xm = 11, ym = 16;
		if (screenSize.width <= 800.0)
			xm = 7, ym = 10;
		screenSize.width -= 64.0;
		xp = (req.width > screenSize.width)
			? 0.0 : (120.0 + (wnum % xm) * DiffStep);
		yp = (req.height > screenSize.height)
			? 0.0 : (20.0 + (wnum % ym) * DiffStep);
		if (xp + req.width > screenSize.width)
			wrect.size.width = screenSize.width - xp;
		if (yp + req.height > screenSize.height)
			wrect.size.height = screenSize.height - yp;
		wrect.origin.x = xp;
		yp = screenSize.height - wrect.size.height - yp;
		wrect.origin.y = (yp > 0.0) ? yp : 0.0;
	}else {
		[thiswindow getFrame: &orig];
		wrect.origin = orig.origin;
		if (req.width > orig.size.width)
			wrect.size.width = orig.size.width;
		if (req.height >= orig.size.height)
			wrect.size.height = orig.size.height;
		else
			wrect.origin.y += orig.size.height - wrect.size.height;
		if (orig.size.width < rsmin.width)
			rsmin.width = orig.size.width;
		if (orig.size.height < rsmin.height)
			rsmin.height = orig.size.height;
	} 
	[thiswindow placeWindow: &wrect];
	[thiswindow setMaxSize: &req];
	[thiswindow setMinSize: &rsmin];
	return self;
}

- initLocateWindow:(const char *)fileName
	Width:(int)width Height:(int)height Num:(int)num 
{
	ToyWin *keytw;

	imageFilename = str_dup(fileName);
	[self locateWindow: width : height init:YES num:num];
	[thiswindow setTitleAsFilename: fileName];
	keytw = [controller keyWindow];
	if (keytw != nil && keytw->miniFlag != mini_MINI)
		[thiswindow orderWindow:NX_BELOW
				relativeTo:[[keytw window] windowNum]];
	else
		[thiswindow orderFront: self];
	NXPing();
	[thiswindow display];
	return self;
}

/* Local */
- Do_reScale: (float)factor
{
	float r;
	NXSize *sz;
	BOOL showmsg;

	r = (scaleFactor > factor)
		? (scaleFactor / factor):(factor / scaleFactor);
	if (r < 1.0025)
		return self;
	sz = [[self toyView] resize: factor];
	if (sz == NULL) {
		NXBeep();
		return self;
	}
	scaleFactor = factor;
	showmsg = (r > 1.7 || (sz->width * sz->height) > 60000);

	if (showmsg) {
		[messagePanel makeKeyAndOrderFront: self];
		[messageText setStringValue:"Resizing..."];
		[messagePanel setFloatingPanel: YES];
		NXPing();
	}
	[self locateWindow: sz->width : sz->height init:NO num:0];
	// DON'T -> [scView sizeTo: sz->width + 21.0 : sz->height + 21.0];
	[thiswindow display];
	if (showmsg) {
		[messagePanel setFloatingPanel: NO];
		[messagePanel close];
	}
	return self;
}

/* Local */
- select_reScale: sender
{
	static float scale[13] = { 0.0, /* never */
		4.0, 3.0, 2.0, 1.5, 1.2, 1.0,
		0.86603, 0.7071, 0.5, 0.33333, 0.25, 0.125 };

	return [self Do_reScale: scale[[sender selectedTag]]];
}

/* Local */
- setScaleValue:(float)val
{
	char buf[24];
	int i = val * 100.0;
	int f = (val * 100.0 - (float)i) * 10.0 + 0.5;
	if (f)
		sprintf(buf, "%d.%01d", i, f);
	else
		sprintf(buf, "%d", i);
	[scaleText setStringValue: buf];
	return self;
}

- reScale: sender
{
	if ([sender selectedTag] == 0) { /* Set... */
		[self setScaleValue: scaleFactor];
		[scalePanel makeKeyAndOrderFront: self];
	}else {
		[scalePanel close];
		[self perform:@selector(select_reScale:) with:sender
			afterDelay: 5 cancelPrevious: YES];
	}
	return self;
}

- fitScale: sender
{
	NXSize	screenSize, *sz;
	float	wf, hf, sc;

	[NXApp getScreenSize: &screenSize];
	sz = [[self toyView] originalSize];
	wf = screenSize.width / sz->width;
	hf = screenSize.height / sz->height;
	sc = ([sender selectedTag] == 0)
		? ((wf < hf) ? wf : hf)    /* Entire Image */
		: ((wf > hf) ? wf : hf);   /* Cover Screen */
	return [self setScaleValue: sc];
}

- setScale: sender
{
	if ([sender selectedTag] == 0) {
		float f = (int)([scaleText floatValue] * 1000.0 + 0.5) / 100000.0;
		[scalePanel close];
		if (f >= 0.01 && f <= 100.0)
			[self Do_reScale: f];
	}else
		[scalePanel close];
	return self;
}

- windowWillMiniaturize:sender toMiniwindow:miniwindow
{
	[[self toyView] clearDraggedLine];
	if (miniFlag == mini_YET)
		[thiswindow setMiniwindowIcon: MiniIcon];
	miniFlag = mini_MINI;
	return self;
}

- windowDidDeminiaturize:sender
{
	miniFlag = mini_DEMINI;
	return self;
}

- windowWillClose:sender
{
	// printf("Window will be freed\n");
	[controller checkWindow: self delete: YES];
	[scView free];
	[thiswindow setDelegate: nil];
	[self free];
	return thiswindow;
}

- windowDidBecomeKey:sender
{
	id tv = [self toyView];
	[thiswindow makeFirstResponder: tv];
	[tv setDraggedLine: self];
	return self;
}

- windowDidExpose:sender
{
	[[self toyView] setDraggedLine: self];
	return self;
}

- windowDidMove:sender
{
	[[self toyView] setDraggedLine: self];
	return self;
}

@end
